package com.bauer.java.spring.aop.aspectJaop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

/**
 * @Author ：rui.wei
 * @Date ：Created in 11:39 2019/1/14
 * @Description： 切面     包含了切点  和增强（advice）
 *
 * 切面本身是不可以被代理的
 *
 * 所有的参数绑定行为  都需要与advice方法中定义的类型匹配上   否则不会执行当前的断言
 * joinpoint 是要放在第一个参数位置上的
 *
 * The @AspectJ style was introduced by the AspectJ project as part of the AspectJ 5 release.
 * Spring interprets the same annotations as AspectJ 5, using a library supplied by AspectJ for pointcut parsing and
 * matching.
 * The AOP runtime is still pure Spring AOP though, and there is no dependency on the AspectJ compiler or weaver.
 *
 * spring 的aop实现采用的是java jdk的动态代理和cglib实现的   只是采用了aspectj的注解去解析pointcut
 *
 * 自调用未触发aop   可以采用如下方法((ProxyBean) AopContext.currentProxy()).aroundTests()  spring官方不推荐使用
 */
@Aspect
@Component
public class AspectDemo {


    /**
     * 切点  也就是我们需要织入代码的地方 代理ProxyBean 中的任意方法
     */
    @Pointcut("execution(* com.bauer.java.spring.aop.aspectJaop.ProxyBean.*(..))")
    public void proxyBeanAnyMethod() {

    }

    @Pointcut("execution(* *..around*(..))")
    public void anyAroundMethod() {

    }

    /**
     * @param proceedingJoinPoint 链接点   可以调用被代理对象在切点范围之中的方法  可以获取方法信息
     */
    @Around(value = "proxyBeanAnyMethod()")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("around start =======");
        Object res = proceedingJoinPoint.proceed();
        System.out.println("around end =======");
        return null;
    }


    /**
     * 绑定入参   通过args 来绑定
     *
     * 绑定的参数个数 需要与  before方法中的参数数量一致否则项目启动会抛出异常（0 formal unbound in pointcut ）
     *
     * , if you modify the preceding advice to receive the join point object, the "argNames" attribute need not include
     * it: 当接收joinpoint时 argNames 无需包含jp
     */
    @Before(value = "execution(* com.bauer.java.spring.aop.aspectJaop.ProxyBean.*(..) ) && args(ss) && this(obj) ",
        argNames = "ss,obj")
    public void before(JoinPoint jp, String ss, Object obj) {
        System.out.println("before todo ======:" + ss);
    }

    /**
     * 当切点抛出异常  after会依旧执行到
     */
    @After(value = "proxyBeanAnyMethod()")
    public void after() {
        System.out.println("after todo ======");
    }

    @AfterReturning(value = "proxyBeanAnyMethod()", returning = "obj")
    public void afterReturning(Object obj) {
        System.out.println("afterReturning return value: " + obj);
    }


    /**
     * 申明的参数的类型 如果与抛出的异常类型不符是不会执行该方法的
     */
    @AfterThrowing(value = "proxyBeanAnyMethod()", throwing = "ex")
    public void afterThrowing(Exception ex) {
        ex.printStackTrace();
    }
}
